package com.kymatrix.kycarbon.xsmd.system.server.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kymatrix.kycarbon.xsmd.system.server.dao.ModuleMapper;
import com.kymatrix.kycarbon.xsmd.system.server.dao.RoleModuleMapper;
import com.kymatrix.kycarbon.xsmd.system.server.model.entity.ModuleEntity;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.module.InsertModuleReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.module.ListQueryModuleResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.module.QueryModuleResp;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.module.SortModuleReq;
import com.kymatrix.kycarbon.xsmd.system.server.model.form.module.UpdateModuleReq;
import com.kymatrix.kycarbon.xsmd.system.server.service.IModuleService;
import com.kymatrix.kycarbon.xsmd.common.business.common.BaseEntity;
import com.kymatrix.kycarbon.xsmd.common.constants.Constant;
import com.kymatrix.kycarbon.xsmd.common.enums.ModuleTypeEnum;
import com.kymatrix.kycarbon.xsmd.common.exception.BusinessException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ModuleServiceImpl extends ServiceImpl<ModuleMapper, ModuleEntity> implements IModuleService {
    
    @Resource
    private RoleModuleMapper roleModuleMapper;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void save(InsertModuleReq moduleReq) {
        if (StrUtil.isNotEmpty(moduleReq.getParentId())) {
            ModuleEntity parent = this.baseMapper.selectById(moduleReq.getParentId());
            if (parent == null) {
                throw new BusinessException("父菜单不存在");
            }
        }
        if (Objects.equals(moduleReq.getType(), ModuleTypeEnum.BUTTON.getCode())
                && StrUtil.isEmpty(moduleReq.getParentId())) {
            throw new BusinessException("按钮的父菜单不能为空");
        }
        ModuleEntity moduleEntity = new ModuleEntity();
        moduleEntity.setParentId(moduleReq.getParentId());
        moduleEntity.setType(moduleReq.getType());
        moduleEntity.setName(moduleReq.getName());
        moduleEntity.setPath(moduleReq.getPath());
        moduleEntity.setIcon(moduleReq.getIcon());
        moduleEntity.setSortNo(0);
        baseMapper.insert(moduleEntity);
    }
    
    private List<ModuleEntity> getAll(String parentId, List<ModuleEntity> list) {
        ModuleEntity rootEntity = this.getById(parentId);
        if (rootEntity != null) {
            list.add(rootEntity);
        }
        List<ModuleEntity> moduleEntities = this.baseMapper.selectByParentId(parentId);
        list.addAll(moduleEntities);
        for (ModuleEntity moduleEntity : moduleEntities) {
            list.addAll(getAll(moduleEntity.getId(), list));
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    @CacheEvict(value = Constant.RedisKeyConstants.MODULE_LIST, key = "#id")
    public void delete(String id) {
        List<ModuleEntity> moduleEntities = getAll(id, new ArrayList<>());
        for (ModuleEntity moduleEntity : moduleEntities) {
            moduleEntity.setDeleted(Constant.DEL_FLAG_DELETE);
            this.baseMapper.updateById(moduleEntity);
        }
        if (CollectionUtil.isNotEmpty(moduleEntities)) {
            List<String> moduleIds = moduleEntities.stream().map(BaseEntity::getId).collect(Collectors.toList());
            this.roleModuleMapper.deleteByModuleIds(moduleIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void update(UpdateModuleReq module) {
        ModuleEntity moduleEntity = this.baseMapper.selectById(module.getId());
        moduleEntity.setParentId(module.getParentId());
        moduleEntity.setType(module.getType());
        moduleEntity.setName(module.getName());
        moduleEntity.setPath(module.getPath());
        moduleEntity.setIcon(module.getIcon());
        this.baseMapper.updateById(moduleEntity);
    }

    @Override
    public List<ListQueryModuleResp> getModuleList() {
        List<ModuleEntity> list = this.baseMapper.selectAll();
        Map<String, List<ModuleEntity>> map = list.stream()
                .filter(a -> StrUtil.isNotEmpty(a.getParentId()))
                .collect(Collectors.groupingBy(ModuleEntity::getParentId));
        List<ModuleEntity> rootList = list.stream().filter(a -> StrUtil.isEmpty(
            a.getParentId())).collect(Collectors.toList());
        List<ListQueryModuleResp> res = new ArrayList<>();
        for (ModuleEntity moduleEntity : rootList) {
            res.add(ListQueryModuleResp.fromEntity(moduleEntity));
        }
        Collections.sort(res);
        for (ListQueryModuleResp resp : res) {
            List<ModuleEntity> moduleEntities = map.get(resp.getId());
            if (moduleEntities != null) {
                for (ModuleEntity moduleEntity : moduleEntities) {
                    get(resp, map, moduleEntity);
                }
            }
        }
        return res;
    }

    private void get(ListQueryModuleResp resp, Map<String, List<ModuleEntity>> map, ModuleEntity entity) {
        ListQueryModuleResp listQueryModuleResp = ListQueryModuleResp.fromEntity(entity);
        resp.getChildrenList().add(listQueryModuleResp);
        Collections.sort(resp.getChildrenList());
        List<ModuleEntity> moduleEntities = map.get(entity.getId());
        if (moduleEntities == null) {
            return;
        }
        for (ModuleEntity moduleEntity : moduleEntities) {
            get(listQueryModuleResp, map, moduleEntity);
        }
    }

    @Override
    public void sort(SortModuleReq req) {
        for (SortModuleReq.SortModule sortModule : req.getSortModules()) {
            ModuleEntity moduleEntity = this.baseMapper.selectById(sortModule.getId());
            if (moduleEntity != null) {
                moduleEntity.setSortNo(sortModule.getSortNo());
                this.baseMapper.updateById(moduleEntity);
            }
        }
    }

    @Override
    @Cacheable(cacheNames = Constant.RedisKeyConstants.MODULE_LIST + "#30", key = "#id", unless = "#result == null")
    public QueryModuleResp getDetail(String id) {
        ModuleEntity moduleEntity = this.baseMapper.selectById(id);
        if (moduleEntity == null) {
            throw new BusinessException("数据不存在");
        }
        QueryModuleResp res = new QueryModuleResp();
        res.setId(moduleEntity.getId());
        res.setParentId(moduleEntity.getParentId());
        res.setName(moduleEntity.getName());
        res.setPath(moduleEntity.getPath());
        res.setType(moduleEntity.getType());
        res.setIcon(moduleEntity.getIcon());
        return res;
    }


}
